#include <stdio.h>
#include <stdlib.h>


/*
	AL RUBI Mustafa 		Groupe D
*/

/* ----------------------------------- */
/*     Definition du type pixel        */
/* ----------------------------------- */


struct sPixel
{
  unsigned char red;
  unsigned char green;
  unsigned char blue;
};
typedef struct sPixel pixel;




/* -------------------------------------------------------------- */
/*     Declarations des procedures que vous pouvez appeler        */
/* (deja ecrites, code disponible pour information apres le main) */
/* -------------------------------------------------------------- */


/* Precondition : nomFichier est le nom d'un fichier au format Bitmap,
   24-bit par pixel (donc pas de palette), non compresse.
   Postconditions : largeur et hauteur contiennent la largeur (nombre de colonnes)
   et la hauteur (nombre de lignes) de l'image, en nombre de pixels.
*/
void lireEntete(const char nomFichier[], unsigned int * largeur, unsigned int * hauteur);



/* Preconditions : tab est un tableau 1D de pixels, suffisamment grand pour contenir
   tous les pixels de l'image. nomFichier est le nom d'un fichier au format Bitmap,
   24-bit par pixel (donc pas de palette), non compresse. largeur et hauteur
   sont les dimensions de l'image en nombre de pixels.
   Postcondition : Chaque case de tab correspond a un pixel de l'image et contient
   ainsi les valeurs RGB de ce pixel. Les premieres cases de tab contiennent la ligne
   de pixels tout en bas de l'image. Les cases suivantes contiennent les pixels de la
   ligne juste au-dessus (2e ligne en partant du bas), etc, jusqu'a la ligne du haut
   de l'image.
*/
void remplirTableauPixelsDepuisFichier(const char nomFichier[], pixel tab[], \
                                       unsigned int largeur, unsigned int hauteur);




/* Preconditions : tab est un tableau contenant largeur*hauteur pixels.
   Postconditions : Un nouveau fichier est cree, nomme comme precise dans la chaine
   de caracteres nomFic. Il est au format Bitmap, 24 bits par pixel,nomFicImage non compresse.
   Si un fichier de ce nom existait deja, il est ecrase.
 */
void ecrireFichier(const char nomFic[], const pixel tab[], \
                   unsigned int largeur, unsigned int hauteur);



/* Precondition: 0 <= numbit <= 7, 0 correspond au bit de poids faible
   Resultat: on recupere le bit numero 'numbit' de 'nombre', c'est-a-dire
   0 ou 1 stocke dans un unsigned char.
*/
unsigned char getIemeBit(unsigned char nombre, unsigned char numbit);




/* Precondition: 0 <= numbit <= 7, 0 correspond au bit de poids faible
   Postcondition: le bit numero 'numbit' de 'nombre' est mis a 0
*/
void setIemeBit0(unsigned char * nombre, unsigned char numbit);




/* Precondition: 0 <= numbit <= 7, 0 correspond au bit de poids faible
   Postcondition: le bit numero 'numbit' de 'nombre' est mis a 1
*/
void setIemeBit1(unsigned char * nombre, unsigned char numbit);




/* -------------------------------------------------------------- */
/*     Ecrivez ci-dessous les codes des procedures demandees      */
/* -------------------------------------------------------------- */

void traitementSepia(const pixel tab[], pixel tabRes[], unsigned int largeur, unsigned int hauteur, unsigned int p)  {
    int i, moy, tmpRed, tmpGreen, tmpBlue;
    for (i = 0; i < (largeur*hauteur); i++)
        {
          moy=(tab[i].red+tab[i].green+tab[i].blue)/3;

          tmpRed = moy-2*p;
          tmpGreen=moy-p;
          tmpBlue=moy+3*p;

          if(tmpRed < 0)
                tmpRed=0;

          if(tmpRed > 255)
                tmpRed=255;

          if(tmpGreen <0)
                tmpGreen=0;

          if(tmpGreen>255)
                tmpGreen=255;

          if(tmpBlue<0)
                tmpBlue=0;

          if(tmpBlue>255)
                tmpBlue=255;
	
	tabRes[i].red=tmpRed;
	tabRes[i].green=tmpGreen;
	tabRes[i].blue=tmpBlue;

        }

}


/* -------------------------- */
/*     Completez le main      */
/* -------------------------- */


int main()
{
  char nomFicImage1[] = "gargouille.bmp";
  unsigned  int larg;
  unsigned  int haut;
  pixel *tabL;
  pixel *tabR; /* Tableau Résultat après traitementSepia*/
  int p=5;

	/* lecture de l'image*/
  lireEntete(nomFicImage1,&larg,&haut) ;
  tabL=(pixel *)malloc(sizeof(pixel)*haut*larg);
  
/* Récupération des pixels de l'image et stocker dans un tableau tabL*/
  remplirTableauPixelsDepuisFichier(nomFicImage1, tabL, larg, haut);
/* Réponse exercice 1 */
  printf("La 10eme colonne de la 7eme ligne contient: 	%d - %d - %d\n",tabL[6*larg+9].red,tabL[6*larg+9].green,tabL[6*larg+9].blue);

  tabR=(pixel *)malloc(sizeof(pixel)*haut*larg);
/* Traitemeent Sépia */
  traitementSepia(tabL, tabR,larg, haut, p);
  ecrireFichier("sepia_Mus.bmp", tabR, larg, haut);
  
  free(tabL);
  free(tabR);


  return 0;

}








/* Procedure auxiliaire utile pour lire les fichiers */
void fskip(FILE *fp, int num_bytes)
{
  int i;
  for (i=0; i<num_bytes; i++) {fgetc(fp);}
}




void lireEntete(const char nomFichier[], unsigned int * largeur, unsigned int * hauteur)
{

  FILE * fic = fopen(nomFichier, "rb");
  unsigned short bitsparpixel = 0;
  unsigned int compression = 0, nbcolorsinpalette = 0, nbimportantcolors = 0;

  if (fgetc(fic)!='B' || fgetc(fic)!='M')
  {
    fclose(fic);
    fprintf(stderr, "%s n'est pas au format BMP.\n",nomFichier);
    exit(EXIT_FAILURE);
  }

  fskip(fic,16);
  fread(largeur, 4, 1, fic);
  fread(hauteur, 4, 1, fic);

  fskip(fic, 2); /* skipping the number of color planes (always 1) */
  fread(&bitsparpixel, 2, 1, fic);

  if(bitsparpixel != 24)
    {
      fclose(fic);
      fprintf(stderr, "Erreur: le nombre de bits par pixel n'est pas 24, \n");
      fprintf(stderr, "ce format d'image n'est pas supporte par ce programme. \n");
      exit(EXIT_FAILURE);
    }
  fread(&compression, 4, 1, fic);
  if(compression != 0)
    {
      fclose(fic);
      fprintf(stderr, "Erreur: le mode de compression n'est pas 0, \n");
      fprintf(stderr, "ce format d'image n'est pas supporte par ce programme. \n");
      exit(EXIT_FAILURE);
    }

  fskip(fic,12);
  fread(&nbcolorsinpalette, 4, 1, fic);
  if(nbcolorsinpalette != 0)
    {
      fclose(fic);
      fprintf(stderr, "Erreur: le nombre de couleurs dans la palette n'est pas 0, \n");
      fprintf(stderr, "ce format d'image n'est pas supporte par ce programme. \n");
      exit(EXIT_FAILURE);
    }

  fread(&nbimportantcolors, 4, 1, fic);
  if(nbimportantcolors != 0)
    {
      fclose(fic);
      fprintf(stderr, "Erreur: le nombre de couleurs importantes n'est pas 0, \n");
      fprintf(stderr, "ce format d'image n'est pas supporte par ce programme. \n");
      exit(EXIT_FAILURE);
    }


  fclose(fic);
}





void remplirTableauPixelsDepuisFichier(const char nomFichier[], pixel tab[], \
                                       unsigned int largeur, unsigned int hauteur)
{
  FILE * fic = fopen(nomFichier, "rb");
  unsigned int ligne, colonne, padding;

  fskip(fic, 54);
  for(ligne = 0; ligne < hauteur; ligne ++)
    {
      for (colonne = 0; colonne < largeur; colonne ++)
        {
          tab[(ligne*largeur) + colonne].red = fgetc(fic);
          tab[(ligne*largeur) + colonne].green = fgetc(fic);
          tab[(ligne*largeur) + colonne].blue = fgetc(fic);
        }

      /* Padding for 4 byte alignment */
      if( (3*largeur)%4 == 0) padding = 0;
      else padding = 4 - ((3*largeur)%4);
      fskip(fic, padding);
    }

  fclose(fic);
}



void ecrireFichier(const char nomFic[], const pixel tab[], \
                   unsigned int largeur, unsigned int hauteur)
{
  FILE * fic = fopen(nomFic, "wb");
  unsigned int monInt;
  unsigned short monShort;
  unsigned char monChar, i;
  unsigned int padding, ligne, colonne, index;

  char format[] = {'B', 'M'};
  unsigned int tailleFic = 54 + largeur*hauteur*3;


  fwrite(format, 1, 2, fic);

  /* size of the file in bytes */
  fwrite(&tailleFic, 4, 1, fic);

  /* Unused, app specific */
  monShort = 0;
  fwrite(&monShort, 2, 1, fic);
  fwrite(&monShort, 2, 1, fic);

  /* Offset for pixel data */
  monInt = 54;
  fwrite(&monInt, 4, 1, fic);

  /* Nb of bytes in the header from this point */
  monInt = 40;
  fwrite(&monInt, 4, 1, fic);

  fwrite(&largeur, 4, 1, fic);
  fwrite(&hauteur, 4, 1, fic);

  /* Nb of color planes (always 1) */
  monShort = 1;
  fwrite(&monShort, 2, 1, fic);

  /* Nb of bits per pixel */
  monShort = 24;
  fwrite(&monShort, 2, 1, fic);

  /* Compression mode */
  monInt = 0;
  fwrite(&monInt, 4, 1, fic);


  /* Size of the raw BMP data (after this header), including padding */
  if( (3*largeur)%4 == 0) padding = 0;
  else padding = 4 - ((3*largeur)%4);
  monInt = (largeur*3 + padding)*hauteur;
  fwrite(&monInt, 4, 1, fic);


  /* Horiz and vertic resolutions (pixel per metre) */
  monInt = 2835;
  fwrite(&monInt, 4, 1, fic);
  fwrite(&monInt, 4, 1, fic);


  /* Numbers of colors in the palette & number of important colors */
  monInt = 0;
  fwrite(&monInt, 4, 1, fic);
  fwrite(&monInt, 4, 1, fic);


  /* Pixel data */

  for(ligne = 0; ligne < hauteur; ligne ++)
    {
      for (colonne = 0; colonne < largeur; colonne ++)
        {
          index = largeur*ligne + colonne;
          fwrite(&tab[index].red, 1, 1, fic);
          fwrite(&tab[index].green, 1, 1, fic);
          fwrite(&tab[index].blue, 1, 1, fic);
        }

      /* Padding for 4 byte alignment */
      if( (3*largeur)%4 == 0) padding = 0;
      else padding = 4 - ((3*largeur)%4);
      monChar = 0;
      for (i = 0; i < padding; i++) fwrite(&monChar, 1, 1, fic);
    }

  fclose(fic);
}




unsigned char getIemeBit(unsigned char nombre, unsigned char numbit)
{
  return (nombre & (1 << numbit)) >> numbit;
}




void setIemeBit0(unsigned char * nombre, unsigned char numbit)
{
  *nombre = (*nombre) & (~(1 << numbit));
}



void setIemeBit1(unsigned char * nombre, unsigned char numbit)
{
  *nombre = (*nombre) | (1 << numbit);
}
